package com.atguigu.lease.web.admin.interceptor;

import com.atguigu.lease.common.context.LoginUser;
import com.atguigu.lease.common.context.LoginUserContext;
import com.atguigu.lease.common.exception.StgyException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.common.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * @Author GQS @Date 2024/9/4/8:44 @Description 身份校验拦截器
 */
@Component
@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {

  @Override
  /**
   * 在处理请求之前执行的拦截器方法 该方法主要用于检查请求中的accessToken，并根据token初始化用户信息 如果accessToken不存在，则抛出管理员登录认证异常
   * 如果accessToken存在，则解析token并设置登录用户信息到上下文
   *
   * @param request HTTP请求对象，用于获取accessToken
   * @param response HTTP响应对象，未在此方法中使用
   * @param handler 即将执行的处理器对象，未在此方法中使用
   * @return 如果accessToken存在并且成功解析，则返回true；否则抛出异常
   * @throws Exception 如果accessToken不存在，则抛出StgyException异常
   */
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    // 从请求头中获取accessToken
    String token = request.getHeader("access_token"); // 这个地方是下划线'_' token名称应该是不区分大小写的
    // System.out.println("token = " + token);
    // 如果accessToken为空，则抛出管理员登录认证异常
    if (token == null) {
      throw new StgyException(ResultCodeEnum.ADMIN_LOGIN_AUTH);
    } else {
      // 解析accessToken
      Claims claims = JwtUtil.parseToken(token);
      // 从解析的claims中获取用户ID和用户名
      Long userId = claims.get("userId", Long.class);
      String username = claims.get("username", String.class);
      // 设置登录用户信息到threadLocal
      LoginUserContext.setLoginUser(new LoginUser(userId, username));
    }
    return true;
  }

  /**
   * 在请求处理完成后执行的拦截器方法 该方法用于在请求处理完成后清理登录用户上下文 避免因为长时间占用或异常导致的资源泄露或状态混乱
   *
   * @param request HTTP请求对象，未在此方法中使用
   * @param response HTTP响应对象，未在此方法中使用
   * @param handler 已执行的处理器对象，未在此方法中使用
   * @param ex 在处理请求过程中是否发生了异常，未在此方法中使用
   * @throws Exception 可能抛出的异常，但当前实现中未使用
   */
  @Override
  public void afterCompletion(
      HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
      throws Exception {
    // 清理登录用户上下文
    LoginUserContext.clear();
  }
}
